package com.wujian.love.utils;


import com.cronutils.model.Cron;
import com.cronutils.model.CronType;
import com.cronutils.model.definition.CronDefinitionBuilder;
import com.cronutils.model.time.ExecutionTime;
import com.cronutils.parser.CronParser;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

/**
 * @className: CronUtils
 * @description: 通过cron表达式计算运行时间
 *
 * @author zhaoshuguang
 * @Date 2019-06-11
 */
public class CronUtils {

    private static final String PATTERN_TIME = "yyyy-MM-dd HH:mm:ss";
    private static final String PATTERN_DATE = "yyyyMMdd";
    private static final ZoneId zoneId = ZoneId.of("Asia/Shanghai");

    /**
     * Parse formatted String "yyyy-MM-dd HH:mm:ss" to ZonedDateTime
     * 
     * @param time
     * @return
     */
    public static ZonedDateTime parse(String time) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN_TIME);
        return LocalDateTime.parse(time, formatter).atZone(zoneId);
    }

    /**
     * Parse formatted String "yyyy-MM-dd" to the start of day as ZonedDateTime
     */
    public static ZonedDateTime parseToStartOfDay(String time) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN_DATE);
        return LocalDate.parse(time, formatter).atStartOfDay().atZone(zoneId);
    }

    /**
     * Parse formatted String "yyyy-MM-dd" to the end of day as ZonedDateTime
     */
    public static ZonedDateTime parseToEndOfDay(String time) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN_DATE);
        return LocalDate.parse(time, formatter).atStartOfDay().plusDays(1).atZone(zoneId).minusSeconds(1L);
    }

    /**
     * @Title formatZonedDateTime
     * @Description: format ZoneDateTime with pattern
     * @Author: zhaoshuguang 16:43 2019-06-11
     * @modify zhaoshuguang 16:43 2019-06-11
     * @param time
     * @param pattern
     * @return java.lang.String
     **/
    public static String formatZonedDateTime(ZonedDateTime time, String pattern) {
        DateTimeFormatter nTZ = DateTimeFormatter.ofPattern(pattern);
        return time.format(nTZ);
    }

    /**
     * @Title formatZonedDate
     * @Description: format ZoneDateTime with Date pattern ：yyyy-MM-dd
     * @Author: zhaoshuguang 16:43 2019-06-11
     * @modify zhaoshuguang 16:43 2019-06-11
     * @param time
     * @return java.lang.String
     **/
    public static String formatZonedDate(ZonedDateTime time) {
        DateTimeFormatter nTZ = DateTimeFormatter.ofPattern(PATTERN_DATE);
        return time.format(nTZ);
    }

    /**
     * @Title formatZonedDateTime
     * @Description: format ZoneDateTime with default pattern ：yyyy-MM-dd
     *               HH:mm:ss
     * @Author: zhaoshuguang 16:43 2019-06-11
     * @modify zhaoshuguang 16:43 2019-06-11
     * @param time
     * @return java.lang.String
     **/
    public static String formatZonedDateTime(ZonedDateTime time) {
        DateTimeFormatter nTZ = DateTimeFormatter.ofPattern(PATTERN_TIME);
        return time.format(nTZ);
    }

    public static ZonedDateTime getLastExecutionTimeAtTime(String cron, ZonedDateTime time) {
        CronParser quartzCronParser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ));
        Cron parsedQuartzCronExpression = quartzCronParser.parse(cron);
        ExecutionTime executionTime = ExecutionTime.forCron(parsedQuartzCronExpression);
        return executionTime.lastExecution(time).get();
    }

    public static ZonedDateTime getLastExecutionTime(String cron) {
        return getLastExecutionTimeAtTime(cron, ZonedDateTime.now(zoneId));
    }

    public static ZonedDateTime getNextExecutionTimeAtTime(String cron, ZonedDateTime time) {
        CronParser quartzCronParser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ));
        Cron parsedQuartzCronExpression = quartzCronParser.parse(cron);
        ExecutionTime executionTime = ExecutionTime.forCron(parsedQuartzCronExpression);
        return executionTime.nextExecution(time).get();
    }

    public static ZonedDateTime getNextExecutionTime(String cron) {
        return getNextExecutionTimeAtTime(cron, ZonedDateTime.now(zoneId));
    }

}
